package com.ymatou.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import org.apache.commons.io.IOUtils;

import com.ymt.core.tool.Logger;
import com.ymt.core.tool.RemoteShellExecutor;

import ch.ethz.ssh2.ChannelCondition;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.SCPClient;
import ch.ethz.ssh2.SCPInputStream;
import ch.ethz.ssh2.SCPOutputStream;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;

public class RemoteShellExecutor2 {

	public RemoteShellExecutor2(String ip, String usr, String pasword) {
		this.ip = ip;
		this.osUsername = usr;
		this.password = pasword;
	}

	private Connection conn;
	/** 远程机器IP */
	private String ip;
	/** 用户名 */
	private String osUsername;
	/** 密码 */
	private String password;
	private String charset = Charset.defaultCharset().toString();

	private static final int TIME_OUT = 1000 * 5 * 60;


	/**
	 * 登录
	 * 
	 * @return
	 * @throws IOException
	 */
	public boolean login() throws IOException {
		conn = new Connection(ip);
		conn.connect();
		boolean success = conn.authenticateWithPassword(osUsername, password);
		return success;
	}

	public void connectClose() throws IOException {
		conn.close();
	}

	/**
	 * 执行脚本
	 * 
	 * @param cmds
	 * @return
	 * @throws Exception
	 */
	public String exec(String cmds) throws Exception {
		StreamGobbler stdOut = null;
		// InputStream stdErr = null;
		String outStr = "";
		// String outErr = "";
		try {
			if (login()) {
				Thread.sleep(500);
				Session session = conn.openSession();
				Logger.debug("exec:" + cmds);
				session.execCommand(cmds);
				// OutputStream stdin = session.getStdin();
				stdOut = new StreamGobbler(session.getStdout());
				outStr = processStream(stdOut, charset);

				// stdErr = new StreamGobbler(session.getStderr());
				// outErr = processStream(stdErr, charset);

				session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT);

				// Logger.debug("outStr=" + outStr);
				// Logger.debug("outErr=" + outErr);

			} else {
				throw new Exception("登录远程机器失败" + ip); // 自定义异常类 实现略
			}
		} finally {
			if (conn != null) {
				conn.close();
			}
			if (stdOut != null) {
				stdOut.close();
			}
			// stdErr.close();
		}
		return outStr;

	}

	/**
	 * @param in
	 * @param charset
	 * @return
	 * @throws IOException
	 * @throws UnsupportedEncodingException
	 */
	private String processStream(StreamGobbler in, String charset) throws Exception {
		StringBuilder sb = new StringBuilder();
		BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(in));
		while (true) {
			String line = stdoutReader.readLine();
			if (line == null)
				break;
			sb.append(line + "\n");
		}
		return sb.toString();
	}

	/**
	 * 远程传输单个文件 会覆盖
	 * 
	 * @param localFile
	 *            本地文件
	 * @param remoteTargetDirectory
	 *            远程目录
	 * @throws IOException
	 */

	public void transferFile(String localFile, String remoteTargetDirectory) throws IOException {
		File file = new File(localFile);
		if (file.isDirectory()) {
			throw new RuntimeException(localFile + "  is not a file");
		}
		String fileName = file.getName();
//		// 覆盖 远程文件
		execCommand("cd " + remoteTargetDirectory + ";rm " + fileName + "; touch " + fileName);

		SCPClient sCPClient = conn.createSCPClient();
		SCPOutputStream scpOutputStream = sCPClient.put(fileName, file.length(), remoteTargetDirectory, "7777");
		FileInputStream localfilestream = new FileInputStream(file);
		byte[] b =new byte[1024];
		boolean r;
		while(localfilestream.read(b)!=-1){  
		 scpOutputStream.write(b, 0, b.length); 
		 scpOutputStream.flush();
		}
		try{
			scpOutputStream.close();
			localfilestream.close();
		}catch (Exception e) {
			System.out.println(e.getMessage());
			// nothing todo
		}
	}

	public void getFile(String remoteFile, String localFile) {
		try {
			File file = new File(localFile);
			if (!file.exists()) {
				file.createNewFile();
			}
			SCPClient client = new SCPClient(conn);
			SCPInputStream inputStream = client.get(remoteFile);
			OutputStream outputStream = new FileOutputStream(localFile);

			int len=-1;
			byte[] bt = new byte[2048];        //可以根据实际情况调整，建议使用1024，即每次读1KB
			while((len=inputStream.read(bt)) !=-1)      {
				outputStream.write(bt,0,len);
				outputStream.flush();
			}
			inputStream.close();
			outputStream.close();
			conn.close();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}

	/**
	 * 传输整个目录 会覆盖
	 * 
	 * @param localFile
	 *            本地文件
	 * @param remoteTargetDirectory
	 *            远程目录
	 * @throws IOException
	 */
	public void transferDirectory(String localDirectory, String remoteTargetDirectory) throws IOException {
		File dir = new File(localDirectory);
		if (!dir.isDirectory()) {
			throw new RuntimeException(localDirectory + " is not directory");
		}

		String[] files = dir.list();
		for (String file : files) {
			if (file.startsWith(".")) {
				continue;
			}
			String fullName = localDirectory + "/" + file;
			if (new File(fullName).isDirectory()) {
				String rdir = remoteTargetDirectory + "/" + file;
				execCommand("mkdir -p " + remoteTargetDirectory + "/" + file);
				transferDirectory(fullName, rdir);
			} else {
				transferFile(fullName, remoteTargetDirectory);
			}
		}

	}

	/**
	 * 提供执行命令方法2 不会执行默认主动登入,需要conn在登入状态下执行 目前用于上传文件功能
	 * 
	 * @param command
	 * @return
	 * @throws IOException
	 */
	public String execCommand(String command) throws IOException {
		Session session = conn.openSession();
		session.execCommand(command, StandardCharsets.UTF_8.toString());
		InputStream streamGobbler = new StreamGobbler(session.getStdout());

		String result = IOUtils.toString(streamGobbler);

		session.waitForCondition(ChannelCondition.EXIT_SIGNAL, Long.MAX_VALUE);

		if (session.getExitStatus().intValue() == 0) {
			Logger.debug("execCommand:  success " + command);
		} else {
			Logger.debug("execCommand :  fail " + command);
		}

		IOUtils.closeQuietly(streamGobbler);
		return result;
	}
	/**
	 * 读取日志流
	 * @param file
	 * @return
	 * @throws IOException
	 */
	public InputStream getLog(String command) throws IOException {
		Session session = conn.openSession();
		session.execCommand(command, StandardCharsets.UTF_8.toString());
		InputStream streamGobbler = new StreamGobbler(session.getStdout());
		return streamGobbler;
	}
	public void close() {
		conn.close();
	}

	public Connection getConnect() {
		return conn;
	}

	public static void main(String args[]) throws Exception {
		RemoteShellExecutor2 rse = new RemoteShellExecutor2("172.16.101.106", "ftpuser", "1qaz@WSX");
		rse.login();
		rse.transferFile("500price.log", "/SIT1/sftcheckfile");
	}
}